package com.pku.smart.notity.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.service.WxPayService;
import com.pku.smart.account.entity.AccountPayChannel;
import com.pku.smart.account.service.IAccountPayChannelService;
import com.pku.smart.config.AliPayConfig;
import com.pku.smart.constant.PayConstant;
import com.pku.smart.log.MyLog;
import com.pku.smart.notity.service.IPayMchNotifyService;
import com.pku.smart.trade.channel.PayChannelFactory;
import com.pku.smart.trade.channel.alipay.AliPayChannelService;
import com.pku.smart.trade.channel.wechatpay.WechatPayChannelService;
import com.pku.smart.trade.entity.TradePayOrder;
import com.pku.smart.trade.entity.TradeRefundOrder;
import com.pku.smart.trade.enums.TradePayRefundStatusEnum;
import com.pku.smart.trade.enums.TradePayStatusEnum;
import com.pku.smart.trade.service.ITradePayOrderService;
import com.pku.smart.trade.service.ITradeRefundOrderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class PayMchNotifyServiceImpl implements IPayMchNotifyService {

    private static final MyLog _log = MyLog.getLog(PayMchNotifyServiceImpl.class);

    private PayChannelFactory factory = new PayChannelFactory();

    @Autowired
    ITradePayOrderService tradePayOrderService;

    @Autowired
    ITradeRefundOrderService tradeRefundOrderService;

    @Autowired
    IAccountPayChannelService payChannelService;

    @Autowired
    AliPayConfig payConfig;

    /**
     * 支付订单通知
     *
     * @param channelOrderNo
     */
    @Override
    public void payOrderSend(String channelOrderNo) {

    }

    /**
     * 处理微信回调
     *
     * @param mchId
     * @param xmlResult
     * @return
     */
    @Override
    public String handleWxPayNotify(String mchId, String xmlResult) {
        _log.info("====== 开始处理微信回调通知 ======");
        try {
            Object object = doValidWxNotify(mchId, xmlResult);
            if (object instanceof String) {
                return WxPayNotifyResponse.fail(object.toString());
            }
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            e.printStackTrace();
            _log.error("微信回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    /**
     * 处理微信退款回调
     *
     * @param mchId
     * @param xmlResult
     * @return
     */
    @Override
    public String handleWxPayRefundNotify(String mchId, String xmlResult) {
        _log.info("====== 开始处理微信退款回调通知 ======");
        try {
            Object object = doValidWxRefundNotify(mchId, xmlResult);
            if (object instanceof String) {
                return WxPayNotifyResponse.fail(object.toString());
            }
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            e.printStackTrace();
            _log.error("微信退款回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    /**
     * 处理支付宝回调
     *
     * @param mchId
     * @param params
     * @return
     */
    @Override
    public String handleAliPayNotify(String mchId, Map params) {
        _log.info("====== 开始处理支付宝支付回调通知 ======");

        String errorMessage;

        String mchOrderNo = String.valueOf(params.get("out_trade_no"));        // 商户订单号
        String totalAmount = String.valueOf(params.get("total_amount"));        // 支付金额

        if (StringUtils.isEmpty(mchOrderNo)) {
            _log.error("商户订单号{}为空", mchOrderNo);
            return PayConstant.TRADE_STATUS_FAILED;
        }
        if (StringUtils.isEmpty(totalAmount)) {
            _log.error("支付金额{}为空", totalAmount);
            return PayConstant.TRADE_STATUS_FAILED;
        }

        TradePayOrder payOrder = tradePayOrderService.getTradePayOrder(mchId, mchOrderNo);
        if (payOrder == null) {
            errorMessage = "支付宝支付订单" + mchOrderNo + "不存在";
            _log.error("支付宝回调验证失败：{}", errorMessage);
            return errorMessage;
        }

        String channelId = payOrder.getChannelId();
        AccountPayChannel payChannel = payChannelService.getPayChannel(mchId, channelId);
        String configParam = payChannel.getParam();
        JSONObject paramObj = JSON.parseObject(configParam);
        String publicKey = paramObj.getString("alipay_public_key");
        Boolean verify = false;
        try {
            verify = AlipaySignature.rsaCheckV1(params,publicKey,AliPayConfig.CHARSET,payConfig.getSignType());
        } catch (AlipayApiException e) {
            e.printStackTrace();
            _log.error("支付宝回调签名验证失败:" + e.getErrMsg());
            return PayConstant.TRADE_STATUS_FAILED;
        }

        _log.info("验证签名");
        if (!verify) {
            _log.error("支付宝回调签名验证失败");
            return PayConstant.TRADE_STATUS_FAILED;
        }
        _log.info("核对金额");
        long aliPayAmt = new BigDecimal(totalAmount).movePointRight(2).longValue();
        long dbPayAmt = payOrder.getAmount().longValue();
        if (dbPayAmt != aliPayAmt) {
            _log.error("支付金额{}验证失败", aliPayAmt);
            return PayConstant.TRADE_STATUS_FAILED;
        }
        _log.info("验证支付通知数据及签名通过");

        String channelOrderNo = String.valueOf(params.get("trade_no"));
        if (payOrder.getStatus() < PayConstant.PAY_STATUS_SUCCESS) {
            payOrder.setErrCode("");
            payOrder.setErrMsg("");
            if (StringUtils.isNotBlank(channelOrderNo)) {
                payOrder.setChannelOrderNo(channelOrderNo);
            }
            payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
            payOrder.setInvokeStatus(TradePayStatusEnum.PAY_STATUS_SUCCESS.name());
            payOrder.setPaySuccTime(new Date());
            tradePayOrderService.updateTradePayOrder(payOrder);
        }
        _log.info("====== 完成处理支付宝支付回调通知 ======");

        return PayConstant.TRADE_STATUS_SUCCESS;
    }

    /**
     * 校验微信支付通知
     *
     * @param mchId   商户号
     * @param xmlData
     * @return 失败 返回错误信息 成功 返回支付订单
     */
    private Object doValidWxNotify(String mchId, String xmlData) {
        String errorMessage = "";
        try {
            WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
            String mchOrderNo = result.getOutTradeNo();
            _log.info("商户定单号：{}", mchOrderNo);
            TradePayOrder payOrder = tradePayOrderService.getTradePayOrder(mchId, mchOrderNo);
            if (payOrder == null) {
                errorMessage = "支付订单" + mchOrderNo + "不存在";
                _log.error("微信回调验证失败：{}", errorMessage);
                return errorMessage;
            }

            String channelOrderNo = result.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
            _log.info("回调返回订单号：{}，微信单号{}，金额：{}", mchOrderNo, channelOrderNo, totalFee);

            if (StringUtils.isNotBlank(payOrder.getChannelOrderNo()) && channelOrderNo.equalsIgnoreCase(payOrder.getChannelOrderNo())) {
                errorMessage = "微信订单号" + channelOrderNo + "与业务系统不一致";
                _log.error(errorMessage);
                return errorMessage;
            }

            if (payOrder.getAmount().intValue() != result.getTotalFee()) {
                errorMessage = "微信订单支付金额" + totalFee + "与业务系统不一致";
                _log.error(errorMessage);
                return errorMessage;
            }

            //微信签名校验
            String channelId = payOrder.getChannelId();
            WechatPayChannelService service = (WechatPayChannelService) factory.build(mchId, channelId);
            WxPayService wxPayService = service.getWxPayService();
            result.checkResult(wxPayService, wxPayService.getConfig().getSignType(), false);

            if (payOrder.getStatus() < PayConstant.PAY_STATUS_SUCCESS) {
                payOrder.setErrCode("");
                payOrder.setChannelOrderNo(channelOrderNo);
                payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
                payOrder.setInvokeStatus(TradePayStatusEnum.PAY_STATUS_SUCCESS.name());
                payOrder.setPaySuccTime(new Date());
                tradePayOrderService.updateTradePayOrder(payOrder);
            }

            _log.info("验证微信通知数据及签名通过");
            return payOrder;
        } catch (Exception e) {
            e.printStackTrace();
            _log.error("微信回调结果异常,异常原因{}", e.getMessage());
            errorMessage = e.getMessage();
            return errorMessage;
        }
    }

    /**
     * 校验微信退款通知
     *
     * @param mchId
     * @param xmlData
     * @return
     */
    private Object doValidWxRefundNotify(String mchId, String xmlData) {
        String errorMessage = "";
        try {
            List<AccountPayChannel> payChannelList = payChannelService.getPayChannelList(mchId);
            if (CollectionUtils.isEmpty(payChannelList)) {
                errorMessage = "商户" + mchId + "没有配置支付渠道";
                _log.info(errorMessage);
                return errorMessage;
            }
            //查找任意一个渠道
            String channelId = payChannelList.get(0).getChannelId();
            WechatPayChannelService service = (WechatPayChannelService) factory.build(mchId, channelId);
            WxPayService wxPayService = service.getWxPayService();
            //获取解密后的退款通知
            WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(xmlData);
            String mchRefundNo = result.getReqInfo().getOutRefundNo();
            _log.info("退款单号：{}", mchRefundNo);

            TradeRefundOrder refundOrder = tradeRefundOrderService.getTradeRefundOrder(mchId, mchRefundNo);
            if (refundOrder == null) {
                errorMessage = "退款订单" + mchRefundNo + "不存在";
                _log.error("微信回调验证失败：{}", errorMessage);
                return errorMessage;
            }

            Integer refundFee = result.getReqInfo().getRefundFee();
            if (refundFee != refundOrder.getRefundAmount().intValue()) {
                errorMessage = "退款订单" + mchRefundNo + "退款金额验证失败：" + refundFee;
                _log.error("微信回调验证失败：{}", errorMessage);
                return errorMessage;
            }
            String channelOrderNo = result.getReqInfo().getRefundId();

            if (PayConstant.REFUND_STATUS_SUCCESS != refundOrder.getStatus()) {
                refundOrder.setStatus(TradePayRefundStatusEnum.REFUND_STATUS_SUCCESS.getCode());
                refundOrder.setResult(result.getReqInfo().getRefundStatus());
                if (StringUtils.isBlank(refundOrder.getChannelOrderNo())) {
                    refundOrder.setChannelOrderNo(channelOrderNo);
                }
                tradeRefundOrderService.updateTradeRefundOrder(refundOrder);
            }

            _log.info("验证微信退款通知数据及签名通过");
            return refundOrder;
        } catch (Exception e) {
            e.printStackTrace();
            _log.error("微信回调结果异常,异常原因{}", e.getMessage());
            errorMessage = e.getMessage();
            return errorMessage;
        }
    }
}
